/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/*
 * firmware.pde arduino firmware für das "cirrus7 one" "Light-Commander" Modul
 *
 * Steuert den LED-Streifen (HL1606) über ein simples serielles Protokoll
 *
 * Arduino Version 0022 
 *
 * Powered by "cirrus7 computing" <http://www.cirrus7.com>
 *
 * License:  This  program  is  free  software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the  Free Software Foundation; either version 3 of the License, or (at your
 * option)  any later version. This program is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * $Author$
 * $Date$
 * $Id$
 * $Revision$
 *
 */

/*
 * Workaround für fehlenden new und delete Operator
 * <http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235348673>
 */

void* operator new(size_t size) { return malloc(size); }
void operator delete(void* ptr) { free(ptr); } 

/* Low-Level Implementation, um LED-Streifen mit HL1606 anzusprechen */
#include <RGBStrip.h>       

/* 
 * Einfacher Parser für ASCII Nachrichtenprotokoll
 * <http://www.arduino.cc/playground/Code/Messenger>
 */
#include <Messenger.h>      

/*
 * Schreiben und Lesen des Arduino EEPROMs: <http://arduino.cc/en/Reference/EEPROM>
 * Der von "cirrus7 computing" für des "Light-Commander" Modul eingesetzte 
 * Arduino pro mini verfügt über insgesamt 512-Byte EEPROM
 */
#include <EEPROM.h>   

/* Helper to get free memory of arduino */
#include <MemoryFree.h>   

/* Messenger Einstellung für Limit der Argumente */
//#define STRING_SIZE 16
//#define MAX_ARGS 5
//#define MESSENGERBUFFERSIZE 128

/* Messenger Objekt instanziieren */
Messenger message = Messenger(); 

/*
 * CHANGELOG:
 * 
 * Offset ist jetzt 2: Bei EEPROM(1) wird jetzt LEDCount gespeichert
 *
 */

/* 
 * Binärpräsentation der unterschiedlichen Farben für RGB-Strip auf 
 * HL1606 Basis.
 *
 * Die Commands und Farben werden mit einem OR verknüpft 
 *
 * BEACHTE: 
 *
 * Es gibt mindestens 2 verschiedene Farbverdrahtungen bei HL1606 LED-Strips
 * Es können beispielsweise grün und blau vertauscht sein.
 * Daher wird im ersten Byte des EEPROMs der Typ des LED-Strips gespeichert
 * Der Default-Typ (siehe unten) hat im EEPROM den Wert "255"
 * Der zweite von uns identifizierte Typ (grün und blau vertauscht) wird im EEPROM
 * als Wert "0" gespeichert.
 * in void setup() wird der Wert ausgelesen und die entsprechenden Farb-Kodierungen,
 * falls nötig überschrieben.
 */

byte Command     = B10000000;
byte Commandx2   = B11000000;   

byte BlueMask    = B00110000;
byte BlueOff     = B00000000;   
byte BlueOn      = B00010000;
byte BlueUp      = B00100000;
byte BlueDown    = B00110000;

byte RedMask     = B00001100;
byte RedOff      = B00000000;
byte RedOn       = B00000100;
byte RedUp       = B00001000;
byte RedDown     = B00001100;

byte GreenMask   = B00000011;
byte GreenOff    = B00000000;
byte GreenOn     = B00000001;
byte GreenUp     = B00000010;
byte GreenDown   = B00000011;

byte Off;
byte Red;
byte Green;
byte Blue;
byte Yellow;
byte Purple;
byte Cyan;
byte White;

/* Standard LED-Stripe Typ (s.o.) wird in void setup(), falls nötig überschrieben */
int stripeType = 255;

/* Anzahl der LEDs. Wird in void setup(), falls nötig überschrieben */
//#define LEDCount 12
unsigned int LEDCount=12;

/* Offset für die speicherbaren Farb-Arrays (in EEPROM(0) wird stripeType gespeichert */
int offset = 2; 

/* Version der cirrus7 light-commander Firmware */
int verMaj = 0;
int verMin = 5;
int verBug = 1;

/* 
 * globales Display-Array 
 * wird von RGBStrip::displaySend() und  RGBStrip::displaySetSection verwendet
 */
//unsigned char Disp[LEDCount];       
unsigned char *Disp;
//Disp = (char *)malloc(sizeof(char)* 3);

/* 
 * globales Display-Array -> hält immer den aktuellen Status 
 * wird für die getter-Methoden verwendet
 */
//unsigned char currDisp[LEDCount];   
unsigned char *currDisp;   

/* 
 * globales Display-Array -> hält durch colorTransition berechnetes Zielarray
 * wird für Überblendungen benutzt (nur intern)
 */
//unsigned char TargetDisp[LEDCount];   
unsigned char *TargetDisp;   


/* 
 * Definition des globalen Pointers strip
 */
//RGBStrip strip(2, 3, 4, 5, LEDCount, Disp);  
RGBStrip* ptrStrip = NULL;


/* 
 * Helper-Funktion: kopiert Disp nach currDisp 
 * Disp wird von RGBStrip::displaySend() und 
 * RGBStrip::displaySetSection verwendet
 */
void cpyArrays() 
{
    for (int i=0; i<LEDCount; i++) {
        currDisp[i] = Disp[i];
    } 
} // end cpyArrays()


/*
 * Helper-Funktion : liest den Stripe Type aus dem EEPROM
 */
unsigned char getStripeType ()
{
    return EEPROM.read(0);
} // end unsigned char getStripeType()

/*
 * Helper-Funktion : liest Anzahl der LEDs aus dem EEPROM
 */
unsigned char getLEDn ()
{
    return EEPROM.read(1);
} // end unsigned char getLEDn()


/*
 * Helper-Funktion: berechnet die Übergangsfarbe bei 
 * bekannter aktueller Farbe und Zielfarbe.
 * Wird für den sanfte Überblendung mit Hilfe des Faders benötigt.
 */
int colorTransition(int currColor, int targetColor) {
    int currRed = currColor & RedMask;
    int targetRed = targetColor & RedMask;
    int resultRed = 0;

    int currGreen = currColor & GreenMask;
    int targetGreen = targetColor & GreenMask;
    int resultGreen = 0;

    int currBlue = currColor & BlueMask;
    int targetBlue = targetColor & BlueMask;
    int resultBlue = 0;

    /* rot-Komponente berechnen */
    if (currRed == targetRed) {
        resultRed = currRed;
    } 
    else if (currRed > targetRed) {
        resultRed = RedDown;
    } 
    else {
        resultRed = RedUp;
    }

    /* grün-Komponente berechnen */
    if (currGreen == targetGreen) {
        resultGreen = currGreen;
    }
    else if (currGreen > targetGreen) {
        resultGreen = GreenDown;
    } 
    else {
        resultGreen = GreenUp;
    }

    /* blau-Komponente berechnen */
    if (currBlue == targetBlue) {
        resultBlue = currBlue;
    }
    else if (currBlue > targetBlue) {
        resultBlue = BlueDown;
    } 
    else {
        resultBlue = BlueUp;
    }

    return Command | resultRed | resultGreen | resultBlue;
} // end colorTransition(int currColor, int targetColor)

/*
 * Helper-Funktion:  
 * zeigt Disp-Array sofort auf dem LED Streifen an
 */
void transitionImmediate()
{
    ptrStrip->displaySend();
    ptrStrip->latch();
    cpyArrays();
} // end void transitionImmediate()

/*
 * Helper-Funktion:  
 * zeigt Disp-Array mit einem sanften Übergang auf LED Streifen an
 * fadeDelay ms Pause zwischen Fader-Aufrufe
 */
void transitionFader( int fadeDelay )
{
    // ok load color table from eeprom and do a transition (from off obviously)
    for (int address=0; address<LEDCount; address++)
    {
        int currColor=currDisp[address];
        int targetColor=Disp[address];
        TargetDisp[address]=targetColor;
        Disp[address]=colorTransition(currColor,targetColor);
        ptrStrip->displaySend();
    } // end for (int address=offset; address<LEDCount+offset; address++)

    ptrStrip->latch();
    ptrStrip->runfader(128, fadeDelay);

    // ok now we finally send target color to all LEDs
    for (int i=0; i<LEDCount; i++) {
        Disp[i] = TargetDisp[i];
    } // end for (int i=0; i<LEDCount; i++) 

    ptrStrip->displaySend();  // send out the values to the LEDs and latch in the values.
    ptrStrip->latch(); //
    // and dont forget to Update CurrDisp!!!
    cpyArrays();
} // end void transitionFader( int fadeDelay )

/*
 * Helper-Funktion:  
 * lädt im EEPROM gespeichertes Array in das Disp-Array
 */
void loadDisplayArray ( int arrayN )
{
    // ok load color table from eeprom and do a transition (from off obviously)
    for (int address=offset+arrayN*LEDCount; address<LEDCount+offset+arrayN*LEDCount; address++)
    {
        Disp[address-offset-arrayN*LEDCount]=EEPROM.read(address);
    } // end for (int address=offset; address<LEDCount+offset; address++)
} // end void loadDisplayArray ( int arrayN )

/*
 * Helper-Funktion:  
 * Wandelt Byte-Repräsentation in color-code
 */
char codeToChar ( byte colorCode ) 
{
    if ( colorCode == Off ) return 'o';
    else if ( colorCode == Red ) return 'r';
    else if ( colorCode == Green ) return 'g';
    else if ( colorCode == Blue ) return 'b';
    else if ( colorCode == Yellow ) return 'y';
    else if ( colorCode == Purple ) return 'p';
    else if ( colorCode == Cyan ) return 'c';
    else if ( colorCode == White ) return 'w'; 
    else return 'u';
} // end char codeToChar ( byte colorCode ) 

/*
 * Helper-Funktion:  
 * Wandelt Color-code in HL1606 Byte Repräsentation
 */
byte charToCode ( char colorChar ) 
{
    if ( colorChar == 'o' ) return Off;
    else if ( colorChar == 'r' ) return Red;
    else if ( colorChar == 'g' ) return Green;
    else if ( colorChar == 'b' ) return Blue;
    else if ( colorChar == 'y' ) return Yellow;
    else if ( colorChar == 'p' ) return Purple;
    else if ( colorChar == 'c' ) return Cyan;
    else if ( colorChar == 'w' ) return White; 
} // end char* charToCode ( byte colorChar ) 

/*
 * RGB Strip is controlled through following commands:
 * 
 * GET Commands:
 * -------------
 * DEPRECATED (use "g d" instead!) g a -> get color-values of all LEDs 
 * DEPRECATED (use "g cdi" instead!) g b [#LED] -> get color-value of LED number #
 *
 * g n -> get number of leds 
 * g v -> get version of firmware
 * g s -> get stripe type (default:255, old:0)    // also used for handshake
 * g t -> get test (only for debug purposes)
 * g h -> get some help information (raw serial output)
 * g f -> get free memory (in bytes)
 *
 * g d -> get color-values of Disp-Array
 * g D -> get color-codes of Disp-Array
 * g cd -> get color-values of currDisp-Array        
 * g CD -> get color-values of currDisp-Array        
 * g cdi [LED#] -> get individual LED#-color of currDisp-array
 * g CDI [LED#] -> get individual LED#-color of currDisp-array
 * g e [ADDRESS#] -> reads #-th byte from EEPROM
 * g ea [ARRAY#] -> get #-th in EEPROM saved array 
 * g EA [ARRAY#] -> get #-th in EEPROM saved array 
 * g el [ARRAY#] -> load in EEPROM saved array to Disp-array 
 * 
 * SET Commands:
 * -------------
 * DEPRECATED (use "s da" instead!) s a [COLOR] -> fill all leds with color-code
 * DEPRECATED (use "s da" instead!) s t [COLOR] [DELAY] -> fill all with color and do a transition from previous color with [DELAY] in ms  
 * DEPRECATED (use "s di" instead!) s b [#LED] [COLOR] -> set color of LED number #
 *
 * s d [COLOR LED0] [COLOR LED1] [COLOR LED2] ... -> set Disp-array (number of arguments depends on LEDCount)
 * s D [COLOR LED0] [COLOR LED1] [COLOR LED2] ... -> set Disp-array (number of arguments depends on LEDCount)
 * s da [COLOR] -> set Disp-array with [COLOR]
 * s DA [COLOR] -> set Disp-array with [COLOR]
 * s di [LED#] [COLOR] -> set LED# of Disp-array individually with [COLOR]
 * s DI [LED#] [COLOR] -> set LED# of Disp-array individually with [COLOR]
 * s e [ADDRESS] [VALUE] -> writes byte to address of EEPROM
 * s (e)c [ARRAY#] -> save currDisp-array to EEPROM  // s c 0 is read when arduino starts
 * s ed [ARRAY#] -> save Disp-array to EEPROM  
 * 
 *
 * TRANSITION Commands:
 * --------------------
 * t i -> immediate transition (switch colors set in Disp)
 * t s [DELAY] -> do a smooth transition to colors set in Disp-Array. [DELAY] between fader in ms
 *
 */


/* Messenger Funktion */
void messageCompleted() {

    /****************************************
     *           GETTER METHODS             *
     ****************************************/
    if ( message.checkString("g") )
    {

        /* g n -> get number of leds */
        if ( message.checkString("n") )
        {
            Serial.print("g n ");
            Serial.print(LEDCount, DEC);
            Serial.print('\r');
        } // end if ( message.checkString("n")

        /* g v -> get version of firmware */
        else if ( message.checkString("v") )
        {
            Serial.print("g v ");
            Serial.print(verMaj,DEC);
            Serial.print('.');
            Serial.print(verMin,DEC);
            Serial.print('.');
            Serial.print(verBug,DEC);
            Serial.print('\r');
        } // end if ( message.checkString("v")

        /* g s -> get stripe type (255):default (0):old */
        else if ( message.checkString("s") )
        {
            Serial.print("g s ");
            Serial.print(stripeType,DEC);
            Serial.print('\r');
        } // end if ( message.checkString("s")
    
        /* g t -> get test (for debug purposes only) */
        else if ( message.checkString("t") )
        {
            Serial.print("g t ");
            Serial.print(Command | BlueOn, DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("t") )

        /* g h -> get help */
        else if ( message.checkString("h") )
        {
            Serial.print("Off -> Command: ");
            Serial.print(Command, DEC);
            Serial.print('\r');

            Serial.print("Red -> Command | RedOn: ");
            Serial.print(Command | RedOn, DEC);
            Serial.print('\r');

            Serial.print("Green -> Command | GreenOn: ");
            Serial.print(Command | GreenOn, DEC);
            Serial.print('\r');

            Serial.print("Blue -> Command | BlueOn: ");
            Serial.print(Command | BlueOn, DEC);
            Serial.print('\r');

            Serial.print("Yellow -> Command | RedOn | GreenOn: ");
            Serial.print(Command | RedOn | GreenOn, DEC);
            Serial.print('\r');

            Serial.print("Purple -> Command | RedOn | BlueOn: ");
            Serial.print(Command | RedOn | BlueOn, DEC);
            Serial.print('\r');

            Serial.print("Cyan -> Command | GreenOn | BlueOn: ");
            Serial.print(Command | GreenOn | BlueOn, DEC);
            Serial.print('\r');

            Serial.print("White -> Command | RedOn | BlueOn | GreenOn: ");
            Serial.print(Command | RedOn | BlueOn | GreenOn, DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("h") )

        /* DEPRECATED (use "g d" instead!) g a -> get color-values of all LEDs */
        else if ( message.checkString("a") )
        {
            Serial.print("g a ");
            for (int i=0;i<LEDCount;i++)
            {
                Serial.print(currDisp[i],DEC); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("t") )

        /* g cd -> get color-values of all LEDs (currDisp-Array) */
        else if ( message.checkString("cd") )
        {
            Serial.print("g cd ");
            for (int i=0;i<LEDCount;i++)
            {
                Serial.print(currDisp[i],DEC); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("cd") )

        /* g CD -> get color-codes of all LEDs (currDisp-Array) */
        else if ( message.checkString("CD") )
        {
            Serial.print("g CD ");
            for (int i=0;i<LEDCount;i++)
            {
                Serial.print(codeToChar(currDisp[i])); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("CD") )

        /* g d -> get color-values of Disp-Array (mainly for debug purposes */
        else if ( message.checkString("d") )
        {
            Serial.print("g d ");
            for (int i=0;i<LEDCount;i++)
            {
                Serial.print(Disp[i],DEC); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("d") )

        /* g D -> get color-codes of Disp-Array (mainly for debug purposes */
        else if ( message.checkString("D") )
        {
            Serial.print("g D ");
            for (int i=0;i<LEDCount;i++)
            {
                Serial.print(codeToChar(Disp[i])); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("D") )

        /* DEPRECATED (use "g cdi" instead)! g b [#LED] -> get value of LED number # */
        else if ( message.checkString("b") )
        {
            int LEDnumber = message.readInt();
            Serial.print("g b ");
            Serial.print(currDisp[LEDnumber], DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("b") )

        /* g cdi [#LED] -> get value of LED number # */
        else if ( message.checkString("cdi") )
        {
            int LEDnumber = message.readInt();
            Serial.print("g cdi ");
            Serial.print(currDisp[LEDnumber], DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("cdi") )

        /* g CDI [#LED] -> get value of LED number # */
        else if ( message.checkString("CDI") )
        {
            int LEDnumber = message.readInt();
            Serial.print("g CDI ");
            Serial.print(codeToChar(currDisp[LEDnumber]));
            Serial.print('\r');
        } // end else if ( message.checkString("CDI") )

        /* g e [address] -> reads byte from address (EEPROM) */
        else if ( message.checkString("e") )
        {
            int address = message.readInt();
            int value = EEPROM.read(address);
            Serial.print("g e ");
            Serial.print(value, DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("e") )

        /* g ea [ARRAY#] -> get in EEPROM saved array  */ 
        else if ( message.checkString("ea") )
        {
            int arrayN = message.readInt();
            Serial.print("g ea ");
            for (int address=offset+arrayN*LEDCount; address<LEDCount+offset+arrayN*LEDCount; address++)
            {
                Serial.print(EEPROM.read(address),DEC);
                Serial.print(" ");
            } // end for (int address=offset; address<LEDCount+offset; address++)
            Serial.print('\r');
        } // end else if ( message.checkString("ea") )

        /* g EA [ARRAY#] -> get in EEPROM saved array  */ 
        else if ( message.checkString("EA") )
        {
            int arrayN = message.readInt();
            Serial.print("g EA ");
            for (int address=offset+arrayN*LEDCount; address<LEDCount+offset+arrayN*LEDCount; address++)
            {
                Serial.print(codeToChar(EEPROM.read(address)));
                Serial.print(" ");
            } // end for (int address=offset; address<LEDCount+offset; address++)
            Serial.print('\r');
        } // end else if ( message.checkString("EA") )

        /* g el [ARRAY#] -> load in EEPROM saved array to Disp-array */ 
        else if ( message.checkString("el") )
        {
            int arrayN = message.readInt();
            loadDisplayArray ( arrayN );        
            Serial.print("g el ");
            Serial.print(arrayN, DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("el") )

        /* g f -> get free memory (in bytes) */
        else if ( message.checkString("f") )
        {
            Serial.print("g f ");
            Serial.print(freeMemory(), DEC);
            Serial.print('\r');
        } // end else if ( message.checkString("f") )
    } // end if ( message.checkString("g") )

    /****************************************
     *       END OF GETTER METHODS          *
     ****************************************/

    /****************************************
     *           SETTER METHODS             *
     ****************************************/
    else if ( message.checkString("s") )
    {
    
        /* s a [COLOR] -> fill all leds with color */
        if ( message.checkString("a") )
        {
            int colCommand = message.readInt();
            ptrStrip->displaySetSection(0,LEDCount-1,colCommand);
            ptrStrip->displaySend();  // send out the values to the LEDs and latch in the values.
            ptrStrip->latch();
            // now that we latched our Disp array, we must update currDisp array ASAP!
            cpyArrays();
        } // end if ( message.checkString("a")

        /* s t [COLOR] [DELAY] -> fill all with color and do a transition from previous color with [DELAY] in ms */
        else if ( message.checkString("t") )
        {
            int targetColor = message.readInt();
            int transitionDelay = message.readInt();
            int transitionColor = colorTransition(currDisp[0], targetColor);
            // send transition color and run fader
            ptrStrip->displaySetSection(0,LEDCount-1,transitionColor);
            ptrStrip->displaySend();  // send out the values to the LEDs and latch in the values.
            ptrStrip->latch();
            ptrStrip->runfader(128,transitionDelay);
            Serial.print(transitionColor);
            // now set target color
            ptrStrip->displaySetSection(0,LEDCount-1,targetColor);
            ptrStrip->displaySend();  // send out the values to the LEDs and latch in the values.
            ptrStrip->latch();
            Serial.print(targetColor);
            // set currDisp to the right color
            cpyArrays();
        } // end if ( message.checkString("t")

        /* DEPRECATED (use "s di" instead!) s b [#LED] [color] -> set color of LED number # (counting from 0) */
        else if ( message.checkString("b") )
        {
            int LED = message.readInt();
            int color = message.readInt();
            ptrStrip->SetLed(LED, color);

            currDisp[LED]=color;

            Serial.print("s b ");
            Serial.print(LED,DEC);
            Serial.print(" ");
            Serial.print(color,DEC);
            Serial.print(" ");
            Serial.print("\r");
        } // end else if ( message.checkString("b") )

        /* s di [#LED] [color] -> set color of LED# */
        else if ( message.checkString("di") )
        {
            int LED = message.readInt();
            int color = message.readInt();

            Disp[LED]=color;

            Serial.print("s di ");
            Serial.print(LED,DEC);
            Serial.print(" ");
            Serial.print(color,DEC);
            Serial.print(" ");
            Serial.print("\r");
        } // end else if ( message.checkString("di") )

        /* s DI [#LED] [color] -> set color of LED# */
        else if ( message.checkString("DI") )
        {
            int LED = message.readInt();
            char colorCode = message.readChar();

            Disp[LED]=charToCode(colorCode);

            Serial.print("s DI ");
            Serial.print(LED,DEC);
            Serial.print(" ");
            Serial.print(colorCode);
            Serial.print(" ");
            Serial.print("\r");
        } // end else if ( message.checkString("DI") )

        /* s d [COLOR LED0] [COLOR LED1] [COLOR LED2] ... -> set Disp-Array (number of arguments depends on LEDCount) */ 
        else if ( message.checkString("d") )
        {
            Serial.print("s d ");
            for (int i=0;i<LEDCount;i++)
            {
                Disp[i] = message.readInt();
                Serial.print(Disp[i],DEC); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("d") )

        /* s D [COLOR LED0] [COLOR LED1] [COLOR LED2] ... -> set Disp-Array (number of arguments depends on LEDCount) */ 
        else if ( message.checkString("D") )
        {
            char colorCode; 
            Serial.print("s D ");
            for (int i=0;i<LEDCount;i++)
            {
                colorCode = message.readChar();
                Disp[i] = charToCode(colorCode);
                Serial.print(colorCode); 
                Serial.print(" ");
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("D") )

        /* s da [COLOR] -> set Disp-Array with [COLOR] */
        else if ( message.checkString("da") )
        {
            int color = message.readInt();
            Serial.print("s da ");
            Serial.print(color,DEC); 
            for (int i=0;i<LEDCount;i++)
            {
                Disp[i] = color;
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("da") )

        /* s DA [COLOR] -> set Disp-Array with [COLOR] */
        else if ( message.checkString("DA") )
        {
            char colorCode = message.readChar();
            Serial.print("s DA ");
            Serial.print(colorCode); 
            for (int i=0;i<LEDCount;i++)
            {
                Disp[i] = charToCode(colorCode);
            }  // end for (int i=0;i<=LEDCount;i++)
            Serial.print('\r');
        } // end else if ( message.checkString("DA") )


        /* s e [address] [value] -> writes byte to address eeprom */
        else if ( message.checkString("e") )
        {
            int address = message.readInt();
            int value = message.readInt();
            EEPROM.write(address,value);
            Serial.print("s e ");
            Serial.print(address,DEC);
            Serial.print(" ");
            Serial.print(value,DEC);
            Serial.print(" ");
            Serial.print("\r");
        }

        /* s (e)c [ARRAY#] -> save current display (currDisp-array) to eeprom */
        else if ( (message.checkString("c")) || (message.checkString("ec")) )
        {
            int arrayN = message.readInt();
            for (int address = offset+arrayN*LEDCount; address<LEDCount+offset+arrayN*LEDCount; address++)
            {
                EEPROM.write(address,currDisp[address - offset - (arrayN*LEDCount) ]);
            }
            Serial.print("s ec ");
            Serial.print(arrayN,DEC);
            Serial.print("\r");
        } // end  if ( message.checkString("c") )

        /* s ed [ARRAY#] -> save display (Disp-array) to eeprom */
        else if ( message.checkString("ed") )
        {
            int arrayN = message.readInt();
            for (int address = offset+arrayN*LEDCount; address<LEDCount+offset+arrayN*LEDCount; address++)
            {
                EEPROM.write(address, Disp[address - offset - (arrayN*LEDCount) ]);
            }
            Serial.print("s ed ");
            Serial.print(arrayN,DEC);
            Serial.print("\r");
        } // end  if ( message.checkString("ed") )
    
     
    } // end else if ( message.checkString("s") )
    /****************************************
     *       END OF SETTER METHODS          *
     ****************************************/
    /****************************************
     *         TRANSITION METHODS            *
     ****************************************/
    else if ( message.checkString("t") )
    {
        /* t i -> immediate transition (switch colors set in Disp) */
        if ( message.checkString("i") )
        {
            transitionImmediate();
            Serial.print("t i\r");
        } // end if ( message.checkString("i") )

        /* t s [DELAY] -> do a smooth transition to colors set in Disp-Array. [DELAY] between fader in ms */
        else if ( message.checkString("s") )
        {
            int transitionDelay = message.readInt();
            transitionFader(transitionDelay);
            Serial.print("t s ");
            Serial.print(transitionDelay, DEC);
            Serial.print("\r");
        } // end if ( message.checkString("i") )
    } // end else if (message.checkString("t") )
    /****************************************
     *     END OF TRANSITION METHODS        *
     ****************************************/

} // end void messageCompleted()


/*******************************************
 *       START OF SETUP METHOD             *
 * setup is called after resetting arduino *
 *******************************************/
void setup() {
    /* read some configuration from eeprom */
    stripeType = getStripeType();
    LEDCount = getLEDn();

    if (stripeType == 0)
    {
        BlueMask   = B00000011;
        BlueOff    = B00000000;
        BlueOn     = B00000001;
        BlueUp     = B00000010;
        BlueDown   = B00000011;

        GreenMask  = B00110000;
        GreenOff   = B00000000;   
        GreenOn    = B00010000;
        GreenUp    = B00100000;
        GreenDown  = B00110000;
    } // end if (stripeType == 0)


    /* now that we know the stripe-type, we can define the basic colors */
    //Off    = Command;
    Off = Command;
    Red    = Command | RedOn;
    Green  = Command | GreenOn;
    Blue   = Command | BlueOn;
    Yellow = Command | RedOn | GreenOn;
    Purple = Command | RedOn | BlueOn;
    Cyan   = Command | GreenOn | BlueOn;
    White  =  Command | RedOn | BlueOn | GreenOn;

    /* <http://diyroboticslab.wordpress.com/2009/09/21/some-pointers-for-memory-allocation/> */
    //Disp = new unsigned char[LEDCount];
    Disp = (unsigned char *)malloc(sizeof(unsigned char) * (LEDCount-1)) ;
    //currDisp = new unsigned char[LEDCount];
    currDisp = (unsigned char *)malloc(sizeof(unsigned char) * (LEDCount-1)) ;
    //TargetDisp = new unsigned char[LEDCount];
    TargetDisp = (unsigned char *)malloc(sizeof(unsigned char) * (LEDCount-1)) ;
    /* 
     * Instanziierung RGBStrip 
     * S, D, C, L, Anzahl der LEDs, globales Display-Array
     */
    ptrStrip = new RGBStrip(2, 3, 4, 5, LEDCount, Disp);

    // just to make sure that we get in clean state - but all LEDs should be off at this point
    ptrStrip->displaySetSection(0,LEDCount-1,Command);
    ptrStrip->displaySend();  // send out the values to the LEDs and latch in the values.
    ptrStrip->latch();
    cpyArrays();

    // load Array from EEPROM
    loadDisplayArray(0);
    transitionFader(5);

    // configure the serial port for 9600 bps data rate.
    Serial.begin(9600);
    message.attach(messageCompleted);

} // end void setup()
/*******************************************
 *         END OF SETUP METHOD             *
 * setup is called after resetting arduino *
 *******************************************/


/* Main Arduino Loop */
void loop() {
    /* Falls es seriellen Input gibt -> verarbeiten! */
    while ( Serial.available( ) ) message.process(Serial.read( ) );
    //while ( Serial.available( ) ) message.process(Serial.read( ) );
} // end void loop() 
